#include "pch.hpp"
#include "WindowHookHelper.hpp"

#include <boostext/smart_ptr.hpp>




// That is the ONLY instance of the WindowHookHelper class
// If anyone (especially myself) creates a second one, the
// application will crash and slap the programmer.
// That instance however is created lazy, meaning that the hook
// is installed when the first MouseHook is created and uninstalled
// when there are no more MouseHook instances
boostext::smart_ptr<WindowHookHelper> m_windowHook;




WindowHookHelper::WindowHookHelper()
	: Hook(&windowHook)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

WindowHookHelper::~WindowHookHelper()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




LRESULT WindowHookHelper::windowProc(int nCode, WPARAM wParam, LPARAM lParam) const
{
	// "If nCode is HC_ACTION, the hook procedure must process the message.
	// If nCode is less than zero, the hook procedure must pass the message
	// to the CallNextHookEx function without further processing and must
	// return the value returned by CallNextHookEx."
	// MSDN - http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
	if(nCode == HC_ACTION)
	{
		// lParam
		// [in] Pointer to a CWPSTRUCT structure that contains details about the message
		// MSDN - http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
		PCWPSTRUCT msg = (PCWPSTRUCT)lParam;

		foreach(const WindowHook *hook, m_hooks)
		{
			if(hook->window() == msg->hwnd)
			{
				hook->windowProc(msg->message, msg->wParam, msg->lParam);
			}
		}
	}

	// It is advised to always return CallNextHookEx, and not what windowProc actually
	return CallNextHookEx(m_hookHandle, nCode, wParam, lParam);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

LRESULT WindowHookHelper::windowHook(int nCode, WPARAM wParam, LPARAM lParam)
{
	// The pointer throws on its own when it's empty
	return m_windowHook->windowProc(nCode, wParam, lParam);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
